Project summary

In 1971 a reciprocal introduction was done between Pod Kopiste island and Pod Mrcaru island in the the South Adriatic Sea. Ten individuals of Podarcis siculus were relocated from Pod Kopiste to Pod Mrcaru, and 10 individuals of Podarcis melisellensis were relocated from Pod Mrcaru to Pod Kopiste. Both islands were inhibited only by the source species at the time - P. siculus on Pod Kopiste and P. melisellensis on Pod Mrcaru.

After ~35 years researchers came back to the islands and witnessed drastic morphological changes between P. siculus on Pod Kopiste, and P. siculus on Pod Mrcaru. To link the genomics with the phenotypic observation we sequenced 47 individuals of P. siculus from each island. This report presents the sequence coverage for the whole genome and the mitoGenome, and basic exploratory analyses.

In all the plots K (Orange) represents the Pod Kopiste population (the source) and M (Blue) represents to Pod Mrcaru population (the relocated population).

Data summary

Data quality

Coverage

Cov<- read_csv(here::here("data/coverage_summary_130120.csv")) %>% 
  filter(!is.na(sample_name)) %>% 
  mutate(real_sample = fct_inorder(real_sample))
ggplot(Cov,aes(real_sample,mean_coverage,fill=island))+
  geom_col(position = "dodge")+
  scale_fill_manual(values=c("#E69F00", "#56B4E9"))+
  theme_bw()+
  theme(axis.ticks.x=element_blank(),
        legend.position = "bottom",
        legend.text = element_text(size = 15),
        legend.title = element_text(size = 15),
        axis.text.x = element_text(angle=90, vjust = 0.5),
        axis.text.y = element_text(size = 15),
        strip.text.x = element_text(size = 15,face="bold"),
        axis.title.x = element_text(size = 15),
        axis.title.y = element_text(size = 15))+
  labs(y = "Coverage (X)", x = "sample",fill = "Sample Island:")

Error rate

LD decay

knitr::include_graphics(here::here("plots/plot_popK_popM_ngsLD.pdf"),dpi = 300)

SFS plots

par(mfrow=c(1,2))
p_realSFS(data_path = "data/angsd/popK_NoIntrogres_noRelated_LargeScaf_noSex_withDepth_150921.saf.sfs",pop_name = "PopK",main = "PopK noIntrogressed individuals")

p_realSFS(data_path = "data/angsd/popM_NoIntorgres_LargeScaf_noSex_withhDepth_150921.saf.sfs",pop_name = "PopM",main = "PopM noIntrogressed individuals")

PCA

PCAngsd_prop_table(data_path = "data/PCA_All_snpPval_LargeScaf_noSex_beagle_withDepth_190321.cov")
PC1 PC2 PC3 PC4 PC5
SD 2.217522 1.059708 1.0498274 1.0400453 1.0311287
Proportion 0.056479 0.012898 0.0126586 0.0124238 0.0122117
Cumulative 0.056479 0.069377 0.0820356 0.0944594 0.1066711
pca.minmaf<- plot_PCAngsd(data_file = "data/PCA_All_snpPval_LargeScaf_noSex_beagle_withDepth_190321.cov",var_data = pop_data,var_names = c("user_id","island"),plot_cols = cols.ps,pc_to_plot = c("PC1","PC2"))+
  xlab("PC1 (5.6%)")+
  ylab("PC2 (1.3%)")
pca.minmaf+
  geom_point(size = 4)

plotly::ggplotly(pca.minmaf)
###pdf("plots/pca_res_new.pdf")
###pca.minmaf+
###  geom_point(size = 4)
###dev.off()

IBS tree

plot_ibsTree(data_file = "data/ibs_All_snpPval_LargeScaf_noSex_withDepth_190321.ibsMat",col.nam = pop_data$user_id,color = cols.ps,pop.data = pop_data,root = T)

Relatedness

PopK

ngsR_popK_data<- read_delim(here::here("data/res_ngsRelate_popK_minmaf_100K_noSex_210321"),delim = "\t") %>% 
  janitor::clean_names()

popK_data<- pop_data %>%
  filter(island=="K") %>% 
  select(user_id) %>% 
  mutate(seq_name = seq(0,45))

ngsRelate.popK<-  ngsR_popK_data %>% 
  left_join(popK_data,by=c("a"="seq_name")) %>% 
  dplyr::rename(ind1=user_id) %>%
  left_join(popK_data,by=c("b"="seq_name")) %>% 
  dplyr::rename(ind2=user_id) %>% 
  relocate(ind1,ind2)

inbredF2<- ngsRelate.popK %>% 
  select(a,b,ind1,ind2,rab) %>% 
  mutate(ind1=naturalsort::naturalfactor(ind1)) %>% 
  mutate(ind2=naturalsort::naturalfactor(ind2)) %>% 
  mutate(pair = paste(ind1,ind2,sep="_")) 

ngs.p4<- ggplot(inbredF2,aes(ind1,ind2,fill= rab,label = pair))+
  geom_tile()+
  theme_minimal()+
  scale_fill_viridis_c(name = "")+
  theme(legend.position = "bottom")
plotly::ggplotly(ngs.p4)

PopM

ngsR_popM_data<- read_delim(here::here("data/res_ngsRelate_popM_minmaf_100K_noSex_210321"),delim = "\t") %>% 
  janitor::clean_names()

popM_data<- pop_data %>%
  filter(island=="M") %>% 
  select(user_id) %>% 
  mutate(seq_name = seq(0,47))

ngsRelate.popM<-  ngsR_popM_data %>% 
  left_join(popM_data,by=c("a"="seq_name")) %>% 
  dplyr::rename(ind1=user_id) %>%
  left_join(popM_data,by=c("b"="seq_name")) %>% 
  dplyr::rename(ind2=user_id) %>% 
  relocate(ind1,ind2)

inbred_popM_F2<- ngsRelate.popM %>% 
  select(a,b,ind1,ind2,rab) %>% 
  mutate(ind1=naturalsort::naturalfactor(ind1)) %>% 
  mutate(ind2=naturalsort::naturalfactor(ind2)) %>% 
  mutate(pair = paste(ind1,ind2,sep="_")) 

ngs.p4.popM<- ggplot(inbred_popM_F2,aes(ind1,ind2,fill= rab,label = pair))+
  geom_tile()+
  theme_minimal()+
  scale_fill_viridis_c(name = "")+
  theme(legend.position = "bottom")
plotly::ggplotly(ngs.p4.popM)

The analyses found the following individuals as related (individuals in bold were removed from introgression analyses):

K3 - K35

K3 - K41

K18 - K45

K7 - K39

K24 - K29

Admixture

We ran admixture using NGSAdmix to analyse how many clusters can be seen among the two populations, excluding the related individuals from PopK. Presented here are results for K=2, K=3 and K=4. There is no quantitative method of choosing the correct K. However, K=2 shows a clear divission between the two populations. K=3 adds another admixture (green) which might represent P. melisellensis, however, it does not align with the results from ABBA-BABA (see bellow).

knitr::include_graphics(here::here("plots/pong_k2_4_admix.png"),dpi = 300)

ABBA-BABA

PS_Pmelis_ref<- read_delim(here::here("data/abbababa_with_Pmlis_orig_jaknif.txt"),delim="\t",col_select = -10) %>% 
  #update the names to fit the names in the popdata file
  mutate(H1 = str_extract(H1,"[^_]*_[^_]*"),H2 = str_extract(H2,"[^_]*_[^_]*"),H3 = str_extract(H3,"[^_]*_[^_]*"))
#create a vector that holds the islands
locIdx_PS<- pop_data2$island
#name it with the ind names that fit the abbababa data
names(locIdx_PS)<- pop_data2$ngi_id
#create a matrix that we will use to generate data for popK with popM as an outgroup in group
group_popK<- matrix(c(rep("K",2), "Pmelis"),ncol=3, byrow=T)

#run the function that renames all the file and keep only the rows that fit the fixed group setting
dstatFixH1H2PopKChangeH3 <- do.call(rbind,apply(group_popK, 1, getDstat3pop, dstatdf=PS_Pmelis_ref,locIdx = locIdx_PS))
leg_scale_popK<-max(c(abs(min(dstatFixH1H2PopKChangeH3$Z)),abs(max(dstatFixH1H2PopKChangeH3$Z))))

plot.PKPK<- plot.data.same.pop(dstatFixH1H2PopKChangeH3,title = "PopK H1, PopK H2, Pmelis H3, Pmur H4, PS ref")
plotly::ggplotly(plot.PKPK)
#create the same for popM
group_popM<- matrix(c(rep("M",2), "Pmelis"),ncol=3, byrow=T)
#do the same for popM as a set group
dstatFixH1H2PopMChangeH3 <- do.call(rbind,apply(group_popM, 1, getDstat3pop, dstatdf=PS_Pmelis_ref,locIdx = locIdx_PS))
leg_scale_popM<-max(c(abs(min(dstatFixH1H2PopMChangeH3$Z)),abs(max(dstatFixH1H2PopMChangeH3$Z))))

plot.PMPM<- plot.data(dstatFixH1H2PopMChangeH3,title = "PopM H1, PopM H2, Pmelis H3, Pmur H4, PS ref")
plotly::ggplotly(plot.PMPM)

Between population Fst

The Fst value between the two populations is 0.034475

Fst scans

Manhattan plot

fst_angsd<- read_delim(here::here("data/popK_popM_slidingWindow_fst_LargeScaf_noM48_nowhichfst_071221"),delim = "\t",col_names = F,skip = 1,col_select = -1) %>% 
  dplyr::rename(chr = X2,midpoint = X3, nsites = X4,PK_PM_fst = X5) %>% 
  mutate(cum_mid = cumsum(midpoint))
# calculate the threshold for outliers and the outliers
my_threshold.uw <- quantile(fst_angsd$PK_PM_fst, 0.995, na.rm = T)

fst_angsd_outlier<- fst_angsd %>% 
  mutate(outlier.uw = ifelse(PK_PM_fst > my_threshold.uw, "outlier", "background"))

outlier_table<- fst_angsd_outlier %>% 
  group_by(outlier.uw) %>% 
  tally()

knitr::kable(outlier_table,align = 'c')
outlier.uw n
background 255523
outlier 1285
# outlier plot
ggplot(fst_angsd_outlier,aes(cum_mid/10000000,PK_PM_fst,color = outlier.uw))+
  geom_point(alpha = 0.75)+
  theme_minimal()+
  theme(legend.position = "none")+
  scale_color_manual(values = c("#000000","#E4572E"))+
  geom_hline(yintercept = my_threshold.uw,lty = 2)+
  xlab("Gbp")+
  ylab("Fst")

Fst peaks

chr.data<- read_delim(here::here("data/above_100kb_noSex_scaff_list.csv"),delim = ",") 

fst_high<- fst_angsd_outlier$PK_PM_fst

true_peak<- fst_peaks(fst_high,limits = c(0.26,0.21))

knitr::kable(fst_angsd_outlier %>% 
  mutate(peak = case_when(PK_PM_fst%in%true_peak$fst_val~"peak",TRUE~"not_peak")) %>% 
  group_by(peak) %>% 
  tally())
peak n
not_peak 256785
peak 23
fst_peak_plot<- fst_angsd_outlier %>% 
  mutate(peak = case_when(PK_PM_fst%in%true_peak$fst_val~"peak",TRUE~"not_peak")) %>% 
  ggplot(aes(cum_mid/10000000,PK_PM_fst,color = peak,size = peak))+
  geom_point(alpha = 0.75)+
  theme_minimal()+
  theme(legend.position = "none")+
  scale_color_manual(values = c("#000000","#960202"))+
  geom_hline(yintercept = my_threshold.uw,lty = 2)+
  xlab("Gbp")+
  ylab("Fst")

####jpeg("plots/fst_peaks_plot2.jpeg",width = 40,height = 30,res = 200)
####fst_peak_plot
####dev.off()

BLAST results

Here are the three localities with the highest Fst between the populations with the genes that area codes for and what this gene might be related to.

knitr::kable(read_csv(here::here("data/forR_peaks_fst_outliers_RN_Method_091221_2.csv")) %>% 
  slice(1:3) %>% 
  select(4,10,11,12,13) %>% 
    rename(trans_id = lifted_clean.gff_res))
PK_PM_fst trans_id explain comment gene_function
0.325397 XM_028723048.1 SIM1 downstream related to regulation of appetite and obesity
0.322867 XM_028734363.1 SRGAP2 upstream Muscle function
0.319335 XM_028729355.1 RHOBTB1 midpoint Muscle function

Demographic modeling

The model that we focused on assumes that there is some introgression from a ghost population in both of the populations that happened after the bottleneck. This is the model we used:

The idea was to calculate the migration and population values that are closest to the reality as we know it and let the optimization to adjust the values to get the most likely model.

We checked whether the model gives a good estimation by comparing the true Fst values with the modeled Fst values. This is what we got:

knitr::kable(df.fst)
X1 FstSS FstW FstU
observed 0.0357929 0.0413785 0.0347378
modelled_C100 0.0393745 0.0449542 0.0303859
modelled_C10 0.0359214 0.0414980 0.0287042

The new values were then used to generate SNPs from 100,000bp simulated DNA fragments for each population. These SNPs were used to calculate the 2dSFS. This was repeated 1,000 and compared to the true Fst peak values we found in the Fst scan. This part is giving some unexpected results and we are still in the process of troubleshooting the problem.

Future planes

The plane now is to write the MS that will focus on our Fst scan based genetic findings and the introgression. Once that is done, we plan to work on the various museum samples that we have to see the change in the genetic composition over time.

LS0tCnRpdGxlOiAiUG9kYXJjaXMgcHJvamVjdCBzdW1tYXJ5IHJlcG9ydCIKYXV0aG9yOiAiTWFyaWEgTm92b3NvbG92IgpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiAlWScpYCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBmb250OiBGaXJhQ29kZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGFwZSkKbGlicmFyeShwaHl0b29scykKbGlicmFyeShndG9vbHMpCm5ub3JtIDwtIGZ1bmN0aW9uKHgpIHgvc3VtKHgpCnNvdXJjZShoZXJlOjpoZXJlKCJzY3JpcHRzL3Bsb3RfcmVhbFNGU19mdW5jdGlvbi5SIikpCnNvdXJjZShoZXJlOjpoZXJlKCJzY3JpcHRzL3Bsb3RfUENBbmdzZF9mdW5jdGlvbi5SIikpCnNvdXJjZShoZXJlOjpoZXJlKCJzY3JpcHRzL0V2b1RyZWVfaWJzTWF0X2Z1bmN0aW9uLlIiKSkKc291cmNlKGhlcmU6OmhlcmUoInNjcmlwdHMvZnN0X3BlYWtfc2VhcmNoX3Jhc211c0FsZ29fZnVuY3Rpb24uUiIpKQpzb3VyY2UoaGVyZTo6aGVyZSgic2NyaXB0cy9yZWFkX2FiYmFfYmFiYV9kYXRhX2Z1bmN0aW9uLlIiKSkKc291cmNlKGhlcmU6OmhlcmUoInNjcmlwdHMvZ2V0RHN0YXQzcG9wX2Z1bmN0aW9uLlIiKSkKcG9wX2RhdGE8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJkYXRhL3BvcF9kYXRhX3dpdGhfYmFtTmFtZXMuY3N2IiksY29sX3NlbGVjdCA9IC0xKQpjb2xzLnBzIDwtIGMoIiNFNjlGMDAiLCAiIzU2QjRFOSIsIiMxMzZkMTUiKQpwb3BfZGF0YTI8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJkYXRhL3BvcF9kYXRhX3dpdGhfYmFtTmFtZXMuY3N2IiksY29sX3NlbGVjdCA9IC0xKSAlPiUgCiAgc2VsZWN0KG5naV9pZCxpc2xhbmQpCgpwb3BfZGF0YTI8LSByYmluZChwb3BfZGF0YTIsYygiU1JSMTQwMDkzOTlfMSIsIlBtZWxpcyIpKQpgYGAKCiMgUHJvamVjdCBzdW1tYXJ5CgpJbiAxOTcxIGEgcmVjaXByb2NhbCBpbnRyb2R1Y3Rpb24gd2FzIGRvbmUgYmV0d2VlbiBQb2QgS29waXN0ZSBpc2xhbmQgYW5kIFBvZCBNcmNhcnUgaXNsYW5kIGluIHRoZSB0aGUgU291dGggQWRyaWF0aWMgU2VhLiBUZW4gaW5kaXZpZHVhbHMgb2YgKlBvZGFyY2lzIHNpY3VsdXMqIHdlcmUgcmVsb2NhdGVkIGZyb20gUG9kIEtvcGlzdGUgdG8gUG9kIE1yY2FydSwgYW5kIDEwIGluZGl2aWR1YWxzIG9mICpQb2RhcmNpcyBtZWxpc2VsbGVuc2lzKiB3ZXJlIHJlbG9jYXRlZCBmcm9tIFBvZCBNcmNhcnUgdG8gUG9kIEtvcGlzdGUuIEJvdGggaXNsYW5kcyB3ZXJlIGluaGliaXRlZCBvbmx5IGJ5IHRoZSBzb3VyY2Ugc3BlY2llcyBhdCB0aGUgdGltZSAtICpQLiBzaWN1bHVzKiBvbiBQb2QgS29waXN0ZSBhbmQgKlAuIG1lbGlzZWxsZW5zaXMqIG9uIFBvZCBNcmNhcnUuCgpBZnRlciB+MzUgeWVhcnMgcmVzZWFyY2hlcnMgY2FtZSBiYWNrIHRvIHRoZSBpc2xhbmRzIGFuZCB3aXRuZXNzZWQgZHJhc3RpYyBtb3JwaG9sb2dpY2FsIGNoYW5nZXMgYmV0d2VlbiAqUC4gc2ljdWx1cyogb24gUG9kIEtvcGlzdGUsIGFuZCAqUC4gc2ljdWx1cyogb24gUG9kIE1yY2FydS4gClRvIGxpbmsgdGhlIGdlbm9taWNzIHdpdGggdGhlIHBoZW5vdHlwaWMgb2JzZXJ2YXRpb24gd2Ugc2VxdWVuY2VkIDQ3IGluZGl2aWR1YWxzIG9mICpQLiBzaWN1bHVzKiBmcm9tIGVhY2ggaXNsYW5kLgpUaGlzIHJlcG9ydCBwcmVzZW50cyB0aGUgc2VxdWVuY2UgY292ZXJhZ2UgZm9yIHRoZSB3aG9sZSBnZW5vbWUgYW5kIHRoZSBtaXRvR2Vub21lLCBhbmQgYmFzaWMgZXhwbG9yYXRvcnkgYW5hbHlzZXMuCgpJbiBhbGwgdGhlIHBsb3RzICoqSyoqIChPcmFuZ2UpIHJlcHJlc2VudHMgdGhlIFBvZCBLb3Bpc3RlIHBvcHVsYXRpb24gKHRoZSBzb3VyY2UpIGFuZCAqKk0qKiAoQmx1ZSkgcmVwcmVzZW50cyB0byBQb2QgTXJjYXJ1IHBvcHVsYXRpb24gKHRoZSByZWxvY2F0ZWQgcG9wdWxhdGlvbikuCgojIERhdGEgc3VtbWFyeQoKIyMgRGF0YSBxdWFsaXR5CgojIyMgQ292ZXJhZ2UKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CkNvdjwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvY292ZXJhZ2Vfc3VtbWFyeV8xMzAxMjAuY3N2IikpICU+JSAKICBmaWx0ZXIoIWlzLm5hKHNhbXBsZV9uYW1lKSkgJT4lIAogIG11dGF0ZShyZWFsX3NhbXBsZSA9IGZjdF9pbm9yZGVyKHJlYWxfc2FtcGxlKSkKZ2dwbG90KENvdixhZXMocmVhbF9zYW1wbGUsbWVhbl9jb3ZlcmFnZSxmaWxsPWlzbGFuZCkpKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNFNjlGMDAiLCAiIzU2QjRFOSIpKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCwgdmp1c3QgPSAwLjUpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSxmYWNlPSJib2xkIiksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpKwogIGxhYnMoeSA9ICJDb3ZlcmFnZSAoWCkiLCB4ID0gInNhbXBsZSIsZmlsbCA9ICJTYW1wbGUgSXNsYW5kOiIpCmBgYAoKIyMjIEVycm9yIHJhdGUgCgohW10oL1VzZXJzL3JsdzM2My9Ecm9wYm94L01hcmlhIFJlc2VhcmNoL0NvbGxhYm9yYXRpb25zL1AuIHNpY3VsdXMgZ2Vub21pY3MgKEEuIEhlcnJlbCwgQW5hbWFya2EsIE1vcnRlbiwgUmFzbXVzKS9Qb2RhcmNpc19zaWN1bHVzX21hcHBpbmcvcGxvdHMvZXJyb3JfcmF0ZV9QU19yZWZfMTkwNTIxX3Bsb3RzT3ZlcmFsbC5wbmcpCgoKIyMjIExEIGRlY2F5CgpgYGB7ciBmaWcuYWxpZ249ImNlbnRlciIsIGZpZy53aWR0aD0yMiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgb3V0LndpZHRoPSIxMDAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgicGxvdHMvcGxvdF9wb3BLX3BvcE1fbmdzTEQucGRmIiksZHBpID0gMzAwKQpgYGAKCiMjIFNGUyBwbG90cwpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGFyKG1mcm93PWMoMSwyKSkKcF9yZWFsU0ZTKGRhdGFfcGF0aCA9ICJkYXRhL2FuZ3NkL3BvcEtfTm9JbnRyb2dyZXNfbm9SZWxhdGVkX0xhcmdlU2NhZl9ub1NleF93aXRoRGVwdGhfMTUwOTIxLnNhZi5zZnMiLHBvcF9uYW1lID0gIlBvcEsiLG1haW4gPSAiUG9wSyBub0ludHJvZ3Jlc3NlZCBpbmRpdmlkdWFscyIpCgpwX3JlYWxTRlMoZGF0YV9wYXRoID0gImRhdGEvYW5nc2QvcG9wTV9Ob0ludG9yZ3Jlc19MYXJnZVNjYWZfbm9TZXhfd2l0aGhEZXB0aF8xNTA5MjEuc2FmLnNmcyIscG9wX25hbWUgPSAiUG9wTSIsbWFpbiA9ICJQb3BNIG5vSW50cm9ncmVzc2VkIGluZGl2aWR1YWxzIikKYGBgCgojIFBDQQoKYGBge3IgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9NywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KUENBbmdzZF9wcm9wX3RhYmxlKGRhdGFfcGF0aCA9ICJkYXRhL1BDQV9BbGxfc25wUHZhbF9MYXJnZVNjYWZfbm9TZXhfYmVhZ2xlX3dpdGhEZXB0aF8xOTAzMjEuY292IikKCnBjYS5taW5tYWY8LSBwbG90X1BDQW5nc2QoZGF0YV9maWxlID0gImRhdGEvUENBX0FsbF9zbnBQdmFsX0xhcmdlU2NhZl9ub1NleF9iZWFnbGVfd2l0aERlcHRoXzE5MDMyMS5jb3YiLHZhcl9kYXRhID0gcG9wX2RhdGEsdmFyX25hbWVzID0gYygidXNlcl9pZCIsImlzbGFuZCIpLHBsb3RfY29scyA9IGNvbHMucHMscGNfdG9fcGxvdCA9IGMoIlBDMSIsIlBDMiIpKSsKICB4bGFiKCJQQzEgKDUuNiUpIikrCiAgeWxhYigiUEMyICgxLjMlKSIpCnBjYS5taW5tYWYrCiAgZ2VvbV9wb2ludChzaXplID0gNCkKcGxvdGx5OjpnZ3Bsb3RseShwY2EubWlubWFmKQojIyNwZGYoInBsb3RzL3BjYV9yZXNfbmV3LnBkZiIpCiMjI3BjYS5taW5tYWYrCiMjIyAgZ2VvbV9wb2ludChzaXplID0gNCkKIyMjZGV2Lm9mZigpCmBgYAoKIyBJQlMgdHJlZSAKCmBgYHtyIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD02LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwbG90X2lic1RyZWUoZGF0YV9maWxlID0gImRhdGEvaWJzX0FsbF9zbnBQdmFsX0xhcmdlU2NhZl9ub1NleF93aXRoRGVwdGhfMTkwMzIxLmlic01hdCIsY29sLm5hbSA9IHBvcF9kYXRhJHVzZXJfaWQsY29sb3IgPSBjb2xzLnBzLHBvcC5kYXRhID0gcG9wX2RhdGEscm9vdCA9IFQpCmBgYAoKIyBSZWxhdGVkbmVzcwoKIyMgUG9wSwpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbmdzUl9wb3BLX2RhdGE8LSByZWFkX2RlbGltKGhlcmU6OmhlcmUoImRhdGEvcmVzX25nc1JlbGF0ZV9wb3BLX21pbm1hZl8xMDBLX25vU2V4XzIxMDMyMSIpLGRlbGltID0gIlx0IikgJT4lIAogIGphbml0b3I6OmNsZWFuX25hbWVzKCkKCnBvcEtfZGF0YTwtIHBvcF9kYXRhICU+JQogIGZpbHRlcihpc2xhbmQ9PSJLIikgJT4lIAogIHNlbGVjdCh1c2VyX2lkKSAlPiUgCiAgbXV0YXRlKHNlcV9uYW1lID0gc2VxKDAsNDUpKQoKbmdzUmVsYXRlLnBvcEs8LSAgbmdzUl9wb3BLX2RhdGEgJT4lIAogIGxlZnRfam9pbihwb3BLX2RhdGEsYnk9YygiYSI9InNlcV9uYW1lIikpICU+JSAKICBkcGx5cjo6cmVuYW1lKGluZDE9dXNlcl9pZCkgJT4lCiAgbGVmdF9qb2luKHBvcEtfZGF0YSxieT1jKCJiIj0ic2VxX25hbWUiKSkgJT4lIAogIGRwbHlyOjpyZW5hbWUoaW5kMj11c2VyX2lkKSAlPiUgCiAgcmVsb2NhdGUoaW5kMSxpbmQyKQoKaW5icmVkRjI8LSBuZ3NSZWxhdGUucG9wSyAlPiUgCiAgc2VsZWN0KGEsYixpbmQxLGluZDIscmFiKSAlPiUgCiAgbXV0YXRlKGluZDE9bmF0dXJhbHNvcnQ6Om5hdHVyYWxmYWN0b3IoaW5kMSkpICU+JSAKICBtdXRhdGUoaW5kMj1uYXR1cmFsc29ydDo6bmF0dXJhbGZhY3RvcihpbmQyKSkgJT4lIAogIG11dGF0ZShwYWlyID0gcGFzdGUoaW5kMSxpbmQyLHNlcD0iXyIpKSAKCm5ncy5wNDwtIGdncGxvdChpbmJyZWRGMixhZXMoaW5kMSxpbmQyLGZpbGw9IHJhYixsYWJlbCA9IHBhaXIpKSsKICBnZW9tX3RpbGUoKSsKICB0aGVtZV9taW5pbWFsKCkrCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MobmFtZSA9ICIiKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKcGxvdGx5OjpnZ3Bsb3RseShuZ3MucDQpCmBgYAoKIyMgUG9wTQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbmdzUl9wb3BNX2RhdGE8LSByZWFkX2RlbGltKGhlcmU6OmhlcmUoImRhdGEvcmVzX25nc1JlbGF0ZV9wb3BNX21pbm1hZl8xMDBLX25vU2V4XzIxMDMyMSIpLGRlbGltID0gIlx0IikgJT4lIAogIGphbml0b3I6OmNsZWFuX25hbWVzKCkKCnBvcE1fZGF0YTwtIHBvcF9kYXRhICU+JQogIGZpbHRlcihpc2xhbmQ9PSJNIikgJT4lIAogIHNlbGVjdCh1c2VyX2lkKSAlPiUgCiAgbXV0YXRlKHNlcV9uYW1lID0gc2VxKDAsNDcpKQoKbmdzUmVsYXRlLnBvcE08LSAgbmdzUl9wb3BNX2RhdGEgJT4lIAogIGxlZnRfam9pbihwb3BNX2RhdGEsYnk9YygiYSI9InNlcV9uYW1lIikpICU+JSAKICBkcGx5cjo6cmVuYW1lKGluZDE9dXNlcl9pZCkgJT4lCiAgbGVmdF9qb2luKHBvcE1fZGF0YSxieT1jKCJiIj0ic2VxX25hbWUiKSkgJT4lIAogIGRwbHlyOjpyZW5hbWUoaW5kMj11c2VyX2lkKSAlPiUgCiAgcmVsb2NhdGUoaW5kMSxpbmQyKQoKaW5icmVkX3BvcE1fRjI8LSBuZ3NSZWxhdGUucG9wTSAlPiUgCiAgc2VsZWN0KGEsYixpbmQxLGluZDIscmFiKSAlPiUgCiAgbXV0YXRlKGluZDE9bmF0dXJhbHNvcnQ6Om5hdHVyYWxmYWN0b3IoaW5kMSkpICU+JSAKICBtdXRhdGUoaW5kMj1uYXR1cmFsc29ydDo6bmF0dXJhbGZhY3RvcihpbmQyKSkgJT4lIAogIG11dGF0ZShwYWlyID0gcGFzdGUoaW5kMSxpbmQyLHNlcD0iXyIpKSAKCm5ncy5wNC5wb3BNPC0gZ2dwbG90KGluYnJlZF9wb3BNX0YyLGFlcyhpbmQxLGluZDIsZmlsbD0gcmFiLGxhYmVsID0gcGFpcikpKwogIGdlb21fdGlsZSgpKwogIHRoZW1lX21pbmltYWwoKSsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhuYW1lID0gIiIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpwbG90bHk6OmdncGxvdGx5KG5ncy5wNC5wb3BNKQpgYGAKCgpUaGUgYW5hbHlzZXMgZm91bmQgdGhlIGZvbGxvd2luZyBpbmRpdmlkdWFscyBhcyByZWxhdGVkIChpbmRpdmlkdWFscyBpbiBib2xkIHdlcmUgcmVtb3ZlZCBmcm9tIGludHJvZ3Jlc3Npb24gYW5hbHlzZXMpOgoKICoqSzMqKiAtIEszNQoKICoqSzMqKiAtIEs0MQoKICoqSzE4KiogLSBLNDUKCiBLNyAtICoqSzM5KioKCiAqKksyNCoqIC0gSzI5CgoKIyBBZG1peHR1cmUKCldlIHJhbiBhZG1peHR1cmUgdXNpbmcgTkdTQWRtaXggdG8gYW5hbHlzZSBob3cgbWFueSBjbHVzdGVycyBjYW4gYmUgc2VlbiBhbW9uZyB0aGUgdHdvIHBvcHVsYXRpb25zLCBleGNsdWRpbmcgdGhlIHJlbGF0ZWQgaW5kaXZpZHVhbHMgZnJvbSBQb3BLLiBQcmVzZW50ZWQgaGVyZSBhcmUgcmVzdWx0cyBmb3IgSz0yLCBLPTMgYW5kIEs9NC4gVGhlcmUgaXMgbm8gcXVhbnRpdGF0aXZlIG1ldGhvZCBvZiBjaG9vc2luZyB0aGUgY29ycmVjdCBLLiBIb3dldmVyLCBLPTIgc2hvd3MgYSBjbGVhciBkaXZpc3Npb24gYmV0d2VlbiB0aGUgdHdvIHBvcHVsYXRpb25zLiBLPTMgYWRkcyBhbm90aGVyIGFkbWl4dHVyZSAoZ3JlZW4pIHdoaWNoIG1pZ2h0IHJlcHJlc2VudCAqUC4gbWVsaXNlbGxlbnNpcyosIGhvd2V2ZXIsIGl0IGRvZXMgbm90IGFsaWduIHdpdGggdGhlIHJlc3VsdHMgZnJvbSBBQkJBLUJBQkEgKHNlZSBiZWxsb3cpLgoKCmBgYHtyIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLndpZHRoPTIyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBvdXQud2lkdGg9IjEwMCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJwbG90cy9wb25nX2syXzRfYWRtaXgucG5nIiksZHBpID0gMzAwKQpgYGAKCiMgQUJCQS1CQUJBCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpQU19QbWVsaXNfcmVmPC0gcmVhZF9kZWxpbShoZXJlOjpoZXJlKCJkYXRhL2FiYmFiYWJhX3dpdGhfUG1saXNfb3JpZ19qYWtuaWYudHh0IiksZGVsaW09Ilx0Iixjb2xfc2VsZWN0ID0gLTEwKSAlPiUgCiAgI3VwZGF0ZSB0aGUgbmFtZXMgdG8gZml0IHRoZSBuYW1lcyBpbiB0aGUgcG9wZGF0YSBmaWxlCiAgbXV0YXRlKEgxID0gc3RyX2V4dHJhY3QoSDEsIlteX10qX1teX10qIiksSDIgPSBzdHJfZXh0cmFjdChIMiwiW15fXSpfW15fXSoiKSxIMyA9IHN0cl9leHRyYWN0KEgzLCJbXl9dKl9bXl9dKiIpKQojY3JlYXRlIGEgdmVjdG9yIHRoYXQgaG9sZHMgdGhlIGlzbGFuZHMKbG9jSWR4X1BTPC0gcG9wX2RhdGEyJGlzbGFuZAojbmFtZSBpdCB3aXRoIHRoZSBpbmQgbmFtZXMgdGhhdCBmaXQgdGhlIGFiYmFiYWJhIGRhdGEKbmFtZXMobG9jSWR4X1BTKTwtIHBvcF9kYXRhMiRuZ2lfaWQKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2NyZWF0ZSBhIG1hdHJpeCB0aGF0IHdlIHdpbGwgdXNlIHRvIGdlbmVyYXRlIGRhdGEgZm9yIHBvcEsgd2l0aCBwb3BNIGFzIGFuIG91dGdyb3VwIGluIGdyb3VwCmdyb3VwX3BvcEs8LSBtYXRyaXgoYyhyZXAoIksiLDIpLCAiUG1lbGlzIiksbmNvbD0zLCBieXJvdz1UKQoKI3J1biB0aGUgZnVuY3Rpb24gdGhhdCByZW5hbWVzIGFsbCB0aGUgZmlsZSBhbmQga2VlcCBvbmx5IHRoZSByb3dzIHRoYXQgZml0IHRoZSBmaXhlZCBncm91cCBzZXR0aW5nCmRzdGF0Rml4SDFIMlBvcEtDaGFuZ2VIMyA8LSBkby5jYWxsKHJiaW5kLGFwcGx5KGdyb3VwX3BvcEssIDEsIGdldERzdGF0M3BvcCwgZHN0YXRkZj1QU19QbWVsaXNfcmVmLGxvY0lkeCA9IGxvY0lkeF9QUykpCmxlZ19zY2FsZV9wb3BLPC1tYXgoYyhhYnMobWluKGRzdGF0Rml4SDFIMlBvcEtDaGFuZ2VIMyRaKSksYWJzKG1heChkc3RhdEZpeEgxSDJQb3BLQ2hhbmdlSDMkWikpKSkKCnBsb3QuUEtQSzwtIHBsb3QuZGF0YS5zYW1lLnBvcChkc3RhdEZpeEgxSDJQb3BLQ2hhbmdlSDMsdGl0bGUgPSAiUG9wSyBIMSwgUG9wSyBIMiwgUG1lbGlzIEgzLCBQbXVyIEg0LCBQUyByZWYiKQpwbG90bHk6OmdncGxvdGx5KHBsb3QuUEtQSykKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2NyZWF0ZSB0aGUgc2FtZSBmb3IgcG9wTQpncm91cF9wb3BNPC0gbWF0cml4KGMocmVwKCJNIiwyKSwgIlBtZWxpcyIpLG5jb2w9MywgYnlyb3c9VCkKI2RvIHRoZSBzYW1lIGZvciBwb3BNIGFzIGEgc2V0IGdyb3VwCmRzdGF0Rml4SDFIMlBvcE1DaGFuZ2VIMyA8LSBkby5jYWxsKHJiaW5kLGFwcGx5KGdyb3VwX3BvcE0sIDEsIGdldERzdGF0M3BvcCwgZHN0YXRkZj1QU19QbWVsaXNfcmVmLGxvY0lkeCA9IGxvY0lkeF9QUykpCmxlZ19zY2FsZV9wb3BNPC1tYXgoYyhhYnMobWluKGRzdGF0Rml4SDFIMlBvcE1DaGFuZ2VIMyRaKSksYWJzKG1heChkc3RhdEZpeEgxSDJQb3BNQ2hhbmdlSDMkWikpKSkKCnBsb3QuUE1QTTwtIHBsb3QuZGF0YShkc3RhdEZpeEgxSDJQb3BNQ2hhbmdlSDMsdGl0bGUgPSAiUG9wTSBIMSwgUG9wTSBIMiwgUG1lbGlzIEgzLCBQbXVyIEg0LCBQUyByZWYiKQpwbG90bHk6OmdncGxvdGx5KHBsb3QuUE1QTSkKYGBgCgoKIyMgQmV0d2VlbiBwb3B1bGF0aW9uIEYqc3QqCgpUaGUgRipzdCogdmFsdWUgYmV0d2VlbiB0aGUgdHdvIHBvcHVsYXRpb25zIGlzICoqMC4wMzQ0NzUqKgoKIyBGc3Qgc2NhbnMKCiMjIE1hbmhhdHRhbiBwbG90CgpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZnN0X2FuZ3NkPC0gcmVhZF9kZWxpbShoZXJlOjpoZXJlKCJkYXRhL3BvcEtfcG9wTV9zbGlkaW5nV2luZG93X2ZzdF9MYXJnZVNjYWZfbm9NNDhfbm93aGljaGZzdF8wNzEyMjEiKSxkZWxpbSA9ICJcdCIsY29sX25hbWVzID0gRixza2lwID0gMSxjb2xfc2VsZWN0ID0gLTEpICU+JSAKICBkcGx5cjo6cmVuYW1lKGNociA9IFgyLG1pZHBvaW50ID0gWDMsIG5zaXRlcyA9IFg0LFBLX1BNX2ZzdCA9IFg1KSAlPiUgCiAgbXV0YXRlKGN1bV9taWQgPSBjdW1zdW0obWlkcG9pbnQpKQojIGNhbGN1bGF0ZSB0aGUgdGhyZXNob2xkIGZvciBvdXRsaWVycyBhbmQgdGhlIG91dGxpZXJzCm15X3RocmVzaG9sZC51dyA8LSBxdWFudGlsZShmc3RfYW5nc2QkUEtfUE1fZnN0LCAwLjk5NSwgbmEucm0gPSBUKQoKZnN0X2FuZ3NkX291dGxpZXI8LSBmc3RfYW5nc2QgJT4lIAogIG11dGF0ZShvdXRsaWVyLnV3ID0gaWZlbHNlKFBLX1BNX2ZzdCA+IG15X3RocmVzaG9sZC51dywgIm91dGxpZXIiLCAiYmFja2dyb3VuZCIpKQoKb3V0bGllcl90YWJsZTwtIGZzdF9hbmdzZF9vdXRsaWVyICU+JSAKICBncm91cF9ieShvdXRsaWVyLnV3KSAlPiUgCiAgdGFsbHkoKQoKa25pdHI6OmthYmxlKG91dGxpZXJfdGFibGUsYWxpZ24gPSAnYycpCiMgb3V0bGllciBwbG90CmdncGxvdChmc3RfYW5nc2Rfb3V0bGllcixhZXMoY3VtX21pZC8xMDAwMDAwMCxQS19QTV9mc3QsY29sb3IgPSBvdXRsaWVyLnV3KSkrCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNzUpKwogIHRoZW1lX21pbmltYWwoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDAwMDAwIiwiI0U0NTcyRSIpKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBteV90aHJlc2hvbGQudXcsbHR5ID0gMikrCiAgeGxhYigiR2JwIikrCiAgeWxhYigiRnN0IikKYGBgCgojIyBGc3QgcGVha3MKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmNoci5kYXRhPC0gcmVhZF9kZWxpbShoZXJlOjpoZXJlKCJkYXRhL2Fib3ZlXzEwMGtiX25vU2V4X3NjYWZmX2xpc3QuY3N2IiksZGVsaW0gPSAiLCIpIAoKZnN0X2hpZ2g8LSBmc3RfYW5nc2Rfb3V0bGllciRQS19QTV9mc3QKCnRydWVfcGVhazwtIGZzdF9wZWFrcyhmc3RfaGlnaCxsaW1pdHMgPSBjKDAuMjYsMC4yMSkpCgprbml0cjo6a2FibGUoZnN0X2FuZ3NkX291dGxpZXIgJT4lIAogIG11dGF0ZShwZWFrID0gY2FzZV93aGVuKFBLX1BNX2ZzdCVpbiV0cnVlX3BlYWskZnN0X3ZhbH4icGVhayIsVFJVRX4ibm90X3BlYWsiKSkgJT4lIAogIGdyb3VwX2J5KHBlYWspICU+JSAKICB0YWxseSgpKQoKZnN0X3BlYWtfcGxvdDwtIGZzdF9hbmdzZF9vdXRsaWVyICU+JSAKICBtdXRhdGUocGVhayA9IGNhc2Vfd2hlbihQS19QTV9mc3QlaW4ldHJ1ZV9wZWFrJGZzdF92YWx+InBlYWsiLFRSVUV+Im5vdF9wZWFrIikpICU+JSAKICBnZ3Bsb3QoYWVzKGN1bV9taWQvMTAwMDAwMDAsUEtfUE1fZnN0LGNvbG9yID0gcGVhayxzaXplID0gcGVhaykpKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjc1KSsKICB0aGVtZV9taW5pbWFsKCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzAwMDAwMCIsIiM5NjAyMDIiKSkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbXlfdGhyZXNob2xkLnV3LGx0eSA9IDIpKwogIHhsYWIoIkdicCIpKwogIHlsYWIoIkZzdCIpCgojIyMjanBlZygicGxvdHMvZnN0X3BlYWtzX3Bsb3QyLmpwZWciLHdpZHRoID0gNDAsaGVpZ2h0ID0gMzAscmVzID0gMjAwKQojIyMjZnN0X3BlYWtfcGxvdAojIyMjZGV2Lm9mZigpCmBgYAoKIyBCTEFTVCByZXN1bHRzCgpIZXJlIGFyZSB0aGUgdGhyZWUgbG9jYWxpdGllcyB3aXRoIHRoZSBoaWdoZXN0IEZzdCBiZXR3ZWVuIHRoZSBwb3B1bGF0aW9ucyB3aXRoIHRoZSBnZW5lcyB0aGF0IGFyZWEgY29kZXMgZm9yIGFuZCB3aGF0IHRoaXMgZ2VuZSBtaWdodCBiZSByZWxhdGVkIHRvLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Ka25pdHI6OmthYmxlKHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvZm9yUl9wZWFrc19mc3Rfb3V0bGllcnNfUk5fTWV0aG9kXzA5MTIyMV8yLmNzdiIpKSAlPiUgCiAgc2xpY2UoMTozKSAlPiUgCiAgc2VsZWN0KDQsMTAsMTEsMTIsMTMpICU+JSAKICAgIHJlbmFtZSh0cmFuc19pZCA9IGxpZnRlZF9jbGVhbi5nZmZfcmVzKSkKYGBgCgojIERlbW9ncmFwaGljIG1vZGVsaW5nCgpUaGUgbW9kZWwgdGhhdCB3ZSBmb2N1c2VkIG9uIGFzc3VtZXMgdGhhdCB0aGVyZSBpcyBzb21lIGludHJvZ3Jlc3Npb24gZnJvbSBhIGdob3N0IHBvcHVsYXRpb24gaW4gYm90aCBvZiB0aGUgcG9wdWxhdGlvbnMgdGhhdCBoYXBwZW5lZCBhZnRlciB0aGUgYm90dGxlbmVjay4gVGhpcyBpcyB0aGUgbW9kZWwgd2UgdXNlZDoKCiFbXSgvVXNlcnMvcmx3MzYzL0Ryb3Bib3gvTWFyaWEgUmVzZWFyY2gvQ29sbGFib3JhdGlvbnMvUC4gc2ljdWx1cyBnZW5vbWljcyAoQS4gSGVycmVsLCBBbmFtYXJrYSwgTW9ydGVuLCBSYXNtdXMpL1BvZGFyY2lzX3NpY3VsdXNfbWFwcGluZy9wbG90cy9EZW1vZ3JhcGhpY19tb2RlbC5wbmcpCgpUaGUgaWRlYSB3YXMgdG8gY2FsY3VsYXRlIHRoZSBtaWdyYXRpb24gYW5kIHBvcHVsYXRpb24gdmFsdWVzIHRoYXQgYXJlIGNsb3Nlc3QgdG8gdGhlIHJlYWxpdHkgYXMgd2Uga25vdyBpdCBhbmQgbGV0IHRoZSBvcHRpbWl6YXRpb24gdG8gYWRqdXN0IHRoZSB2YWx1ZXMgdG8gZ2V0IHRoZSBtb3N0IGxpa2VseSBtb2RlbC4KCldlIGNoZWNrZWQgd2hldGhlciB0aGUgbW9kZWwgZ2l2ZXMgYSBnb29kIGVzdGltYXRpb24gYnkgY29tcGFyaW5nIHRoZSB0cnVlIEYqc3QqIHZhbHVlcyB3aXRoIHRoZSBtb2RlbGVkIEYqc3QqIHZhbHVlcy4gVGhpcyBpcyB3aGF0IHdlIGdvdDoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmRmLmZzdDwtIGFzLmRhdGEuZnJhbWUobWF0cml4KGRhdGEgPSBOQSxuY29sID0gNCxucm93ID0gMykpCnJvdy5uPC0gYygib2JzZXJ2ZWQiLCJtb2RlbGxlZF9DMTAwIiwibW9kZWxsZWRfQzEwIikKbmFtZXMoZGYuZnN0KTwtIGMoIlgxIiwiRnN0U1MiLCJGc3RXIiwiRnN0VSIpCmRmLmZzdCRYMTwtIHJvdy5uCgpzb3VyY2UoaGVyZTo6aGVyZSgic2NyaXB0cy9mdW5jdGlvbnNfZm9yX2ZzdF9mcm9tXzJkU0ZTLlIiKSkKIyMjIyMgTW9kZWwgRnN0IEMxMDAgIyMjIyMjIwpmdWxsPC1zY2FuKGhlcmU6OmhlcmUoImRhdGEvbW9kZWw5OF9NU0ZTLnR4dCIpLHNraXAgPSAyKQpmdWxsTTwtbWF0cml4KGZ1bGwsIG5jb2w9OTUsIG5yb3c9ODUsIGJ5cm93PVQpCmZ1bGxNWzE6NSwxOjVdCm9yZy5mc3QubW9kZWw8LSBnZXRGc3QoZnVsbE0pCmRmLmZzdFsyLDJdPC0gb3JnLmZzdC5tb2RlbApyZXkuZnN0PC0gZ2V0UmV5bm9sZHNGc3QoZnVsbE0pCnN0cihyZXkuZnN0KQpkZi5mc3RbMiwzXTwtIHJleS5mc3RbWzFdXQpkZi5mc3RbMiw0XTwtIHJleS5mc3RbWzJdXQoKIyMjIyMgTW9kZWwgRnN0IEMxMCAjIyMjIwpmdWxsPC1zY2FuKGhlcmU6OmhlcmUoImRhdGEvbW9kZWw5OV9NU0ZTLnR4dCIpLHNraXAgPSAyKQpmdWxsTTwtbWF0cml4KGZ1bGwsIG5jb2w9OTUsIG5yb3c9ODUsIGJ5cm93PVQpCmZ1bGxNWzE6NSwxOjVdCm9yZy5mc3QubW9kZWw8LSBnZXRGc3QoZnVsbE0pCmRmLmZzdFszLDJdPC0gb3JnLmZzdC5tb2RlbApyZXkuZnN0PC0gZ2V0UmV5bm9sZHNGc3QoZnVsbE0pCnN0cihyZXkuZnN0KQpkZi5mc3RbMywzXTwtIHJleS5mc3RbWzFdXQpkZi5mc3RbMyw0XTwtIHJleS5mc3RbWzJdXQoKIyMjIyMgVHJ1ZSBGc3QgIyMjIyMKdHJ1ZS5kYXRhPC0gc2NhbihoZXJlOjpoZXJlKCJkYXRhL3BvcEsucG9wTV8yZHNmc19MYXJnZVNjYWZfbm9SZWxhdGVUUlVFX25vTTQ4XzIzMDIyMi5tbCIpKQp0cnVlLmRhdGEubTwtIG1hdHJpeCh0cnVlLmRhdGEsIG5jb2w9OTUsIG5yb3c9ODUsIGJ5cm93PVQpCnRydWUuZGF0YS5tWzE6NSwxOjVdCnRydWUuZGF0YS51bmZsYXQ8LSB1bmZsYXRlbl9tYXRyaXgodHJ1ZS5kYXRhLGRpbXMgPSBjKDk1LDg1KSkKdHJ1ZS5kYXRhLnVuZmxhdFsxOjUsMTo1XQoKb2JzLmZzdC5vcmc8LSBnZXRGc3QodHJ1ZS5kYXRhLm0pCmdldEZzdCh0cnVlLmRhdGEudW5mbGF0KQoKcmV5LmZzdC5vYnM8LSBnZXRSZXlub2xkc0ZzdCh0cnVlLmRhdGEubSkKCmRmLmZzdFsxLDJdPC0gb2JzLmZzdC5vcmcKZGYuZnN0WzEsM108LSByZXkuZnN0Lm9ic1tbMV1dCmRmLmZzdFsxLDRdPC0gcmV5LmZzdC5vYnNbWzJdXQoKYGBgCgpgYGB7cn0Ka25pdHI6OmthYmxlKGRmLmZzdCkKYGBgCgoKVGhlIG5ldyB2YWx1ZXMgd2VyZSB0aGVuIHVzZWQgdG8gZ2VuZXJhdGUgU05QcyBmcm9tIDEwMCwwMDBicCBzaW11bGF0ZWQgRE5BIGZyYWdtZW50cyBmb3IgZWFjaCBwb3B1bGF0aW9uLiBUaGVzZSBTTlBzIHdlcmUgdXNlZCB0byBjYWxjdWxhdGUgdGhlIDJkU0ZTLiBUaGlzIHdhcyByZXBlYXRlZCAxLDAwMCBhbmQgY29tcGFyZWQgdG8gdGhlIHRydWUgRipzdCogcGVhayB2YWx1ZXMgd2UgZm91bmQgaW4gdGhlIEYqc3QqIHNjYW4uIFRoaXMgcGFydCBpcyBnaXZpbmcgc29tZSB1bmV4cGVjdGVkIHJlc3VsdHMgYW5kIHdlIGFyZSBzdGlsbCBpbiB0aGUgcHJvY2VzcyBvZiB0cm91Ymxlc2hvb3RpbmcgdGhlIHByb2JsZW0uCgojIEZ1dHVyZSBwbGFuZXMKClRoZSBwbGFuZSBub3cgaXMgdG8gd3JpdGUgdGhlIE1TIHRoYXQgd2lsbCBmb2N1cyBvbiBvdXIgRnN0IHNjYW4gYmFzZWQgZ2VuZXRpYyBmaW5kaW5ncyBhbmQgdGhlIGludHJvZ3Jlc3Npb24uIE9uY2UgdGhhdCBpcyBkb25lLCB3ZSBwbGFuIHRvIHdvcmsgb24gdGhlIHZhcmlvdXMgbXVzZXVtIHNhbXBsZXMgdGhhdCB3ZSBoYXZlIHRvIHNlZSB0aGUgY2hhbmdlIGluIHRoZSBnZW5ldGljIGNvbXBvc2l0aW9uIG92ZXIgdGltZS4=